package com.jian.mygame;

import java.util.ArrayList;
import java.util.Collections;
import java.util.ListIterator;

import org.jbox2d.common.Vec2;

import android.util.Log;

public class MyPolygon extends Object{
	
    class MyVertex extends Vec2 implements Comparable<MyVertex> {
    	float mDistance = 0.0f; //Distance to previous vertex
    	float mAngle = 0.0f; //Angle to previous vertex
    	    	
    	void setDistance( float distance ){
    		mDistance = distance;
    	}
    	
    	void setAngle( float angle ){
    		mAngle = angle;
    	}
    	
    	public String toString(){
    		String str = new String();
    		
    		str = "x: " + x + " / y:" + y + " / angle: " + mAngle + " / dist: " + mDistance;
    		
    		return str;
    	}

		@Override
		public int compareTo(MyVertex that) {
			// TODO Auto-generated method stub
	    	int result;
	    	if(mDistance < that.mDistance )
	    		//Less than that
	    	    result= -1;
	    	else if(mDistance > that.mDistance)
	    	    //Greater than that
	    	    result = 1;
	    	else
	    	    // Equal
	    	    result = 0;
	    	return result;
		}
    }
    
    Vec2[] mVec = null;
    ArrayList<MyVertex> mVecList = new ArrayList<MyVertex>();
	public MyPolygon( Vec2[] vec) {
		// TODO Auto-generated constructor stub
		mVec = vec;
		transformToVecList();
		dump();
	}
	
	private ArrayList<MyVertex> transformToVecList(){
		return transformToVecList(mVec);
	}
	
	private ArrayList<MyVertex> transformToVecList(Vec2[] vec){
		Vec2 lastV = vec[vec.length-1];
		Vec2 originV = vec[0];
		float angle = 0.0f;
		
        for( int i = 0; i< vec.length; i++ ) {
        	Vec2 v = vec[i];
			MyVertex vertex = new MyVertex();
			vertex.set(v);
			vertex.setDistance( v.clone().sub(lastV).length());
			angle = MyUtil.calculateAngle(v.x-originV.x, v.y-originV.y);
			vertex.setAngle(angle);
			mVecList.add(vertex);
			lastV = v;
		}
        
        return mVecList;
	}
	
	protected Vec2[] filterVertex(){
		//mVec = filterVertexAngle(mVec);
		filterVertexAngle();
		dump();
		filterVertexSampleNumber();
		dump();
		return mVecList.toArray( new Vec2[mVecList.size()] );
	}
	
	private void dump(){
		ListIterator<MyVertex> it = mVecList.listIterator();
		Log.d("MyPolygon", "-------Dump Begin---------");
		while( it.hasNext() ){
			MyVertex curVertex = it.next();
			Log.d("MyPolygon", "dump: "+ curVertex.toString());
		}
		Log.d("MyPolygon", "-------Dump End-----------");
	}
	
	private void filterVertexAngle(){
		float angleThreshold = (float)(30 * Math.PI/180);
		//ListIterator<MyVertex> it = mVecList.listIterator();
		MyVertex lastVertex = mVecList.get(mVecList.size()-1);
		
		//while( it.hasNext() ){
		for( int index = 0; index < mVecList.size(); index++){
			//MyVertex curVertex = it.next();
			//int index = mVecList.indexOf(curVertex);
			MyVertex curVertex = mVecList.get(index);
			
			Log.d("MyPolygon", "--------<"+ index + ">-------");
			Log.d("MyPolygon", "LastVertex: "+ lastVertex.toString());
			Log.d("MyPolygon", "curVertex: "+ curVertex.toString());
			//if( Math.abs(curVertex.mAngle-lastVertex.mAngle)>angleThreshold ) {
			if( index == 0 ){
				Log.d("MyPolygon", "Origin");
			} else {
				if( !(curVertex.mAngle<lastVertex.mAngle) ) {
					//Good Polygon
					//do nothing
					Log.d("MyPolygon", "Go to next");
				} else {
					//Bad Polygon
					//Replace the last vertex with the new one
					Log.d("MyPolygon", "Remove previous");
					
					//Remove the previous one
					if( index > 0 ) {
						mVecList.remove(index-1);
						//it.remove();
						//Calculate Last Angle and distance again
						curVertex.setDistance( curVertex.clone().sub(lastVertex).length());
						//float angle = MyUtil.calculateAngle(curVertex.x-lastVertex.x, curVertex.y-lastVertex.y);
						//curVertex.setAngle(angle);
					}
				}
			}
			lastVertex = curVertex;
			//}
		}
	}
	
    private void filterVertexSampleNumber(){
    	
		// The maximal size of the array is controlled by b2_maxPolygonVertices 
		//which has a default value of 8. This is sufficient to describe most convex polygons.
		//float vAngle = MyUtil.calculateAngle(v.x-lastV.x, v.y-lastV.y);
    	while( mVecList.size() > 8 ){
            Log.d("MyPolygon", "mVecList.size(): " + mVecList.size());
    		filterVertexRemoveOneVertex();
    	}
    }
    
    private void filterVertexRemoveOneVertex(){
    	//Vec2[] vec = mVec;
        @SuppressWarnings("unchecked")
		ArrayList<MyVertex> vertexList = (ArrayList<MyVertex>) mVecList.clone(); 
        
        //Sort
        Collections.sort(vertexList);
        
        //Remove the first(smallest) element
        mVecList.remove(vertexList.get(0));
    }

    static protected Vec2[] filterVertexAngle(Vec2[] vec){
        float lastVAngle = (float) (-Math.PI);
        //float lastDistance = 0f;
        float angleThreshold = (float)(15 * Math.PI/180);

        ArrayList<Vec2> newVec = new ArrayList<Vec2>(); 
		Vec2 lastV= vec[0];
        newVec.add(lastV);
        //shape.addVertex(new Vec2(vec[0].x/RATE, vec[0].y/RATE));
        Log.d("MyPolygon", "vec[].lengh: " + vec.length);
        Log.d("MyPolygon", "newVec.size: " + newVec.size());
		for( Vec2 v: vec ) {
			float vAngle = MyUtil.calculateAngle(v.x-lastV.x, v.y-lastV.y);
			
			Log.d("MyPolygon", "---vec[] x: " + v.x + " /y: " + v.y + "---");
			if( Math.abs(vAngle-lastVAngle)>angleThreshold ) {
				Log.d("MyPolygon", "vAngle: " + vAngle + " / LastAngle: " + lastVAngle );
				if( vAngle>lastVAngle ) {
					//Good Polygon
					//shape.addVertex(new Vec2(v.x/RATE, v.y/RATE));
					Log.d("MyPolygon", "newVec Add");
					newVec.add(v);
					lastVAngle = vAngle;
					lastV = v;
				} else {
					//Bad Polygon
					//Replace the last vertex with the new one
					Log.d("MyPolygon", "newVec Replace");
					newVec.set(newVec.size()-1, v);
					//Calculate Last Angle again
					lastV = newVec.get(newVec.size()-2);
					lastVAngle = MyUtil.calculateAngle(v.x-lastV.x, v.y-lastV.y);;
					lastV = v;
				}
				Log.d("MyPolygon", "newVec.size: " + newVec.size());
				Log.d("MyPolygon", "newVec[] x: " + v.x + " /y: " + v.y);
			}
		}
        
	    Vec2[] vec_ret = new Vec2[newVec.size()];
    	return newVec.toArray(vec_ret);
    }
    
    static protected Vec2[] filterVertexDistance(Vec2[] vec){
        ArrayList<Vec2> newVec = new ArrayList<Vec2>(); 
		Vec2 lastV= vec[0];
        newVec.add(lastV);
        //shape.addVertex(new Vec2(vec[0].x/RATE, vec[0].y/RATE));
        Log.d("MyPolygon", "vec[].lengh: " + vec.length);
        Log.d("MyPolygon", "newVec.size: " + newVec.size());
		for( Vec2 v: vec ) {
			float distance = v.clone().sub(lastV).length(); 
			
			Log.d( "MyPolygon", "---vec[] x: " + v.x + " /y: " + v.y + "---");
			if( distance > 10 ) {
				Log.d("MyPolygon", "newVec Add");
				newVec.add(v);
				lastV = v;
				Log.d("MyPolygon", "newVec.size: " + newVec.size());
				Log.d("MyPolygon", "newVec[] x: " + v.x + " /y: " + v.y);
			}
		}
		
	    Vec2[] vec_ret = new Vec2[newVec.size()];
    	return newVec.toArray(vec_ret);
    }
}
